// This source code demonstrates how to connect to Access 2007
// .accdb database from C++ using the OLE DB Data Access Technology.
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
// This sample code is provided to illustrate a concept and 
// should not be used in applications or Web sites, as it 
// may not illustrate the safest coding practices. Microsoft 
// assumes no liability for incidental or consequential damages 
// should the sample code be used for purposes 
// other than as intended.

#include <atldbcli.h>
#include <atldbsch.h>
#include <iostream>

using namespace std;

// Data Access Method used in this sample
const char* DAM = "ATL OLE DB";

// Connection string for OLE DB 
LPCOLESTR lpcOleConnect = 
    L"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\\Northwind 2007.accdb;User Id=admin;Password=;";


int _tmain(int argc, _TCHAR* argv[])
{
    // Initialize the Component Object Module Library (COM)
    HRESULT hr = CoInitialize(NULL);
    if (FAILED(hr))
    {
        cout<<DAM<<": Failed to CoInitialize() COM."<<endl;
        return hr;
    }

    // To initialize the connection to a database using an OLE DB provider, 
    // two ATL classes are needed: CDataSource and CSession;
    CDataSource dbDataSource;
    CSession dbSession;

    // Uses ATL's string conversion macros to convert between character encodings
    USES_CONVERSION;

    // Open the connection and initialize the data source specified by the passed 
    // initialization string.
    hr = dbDataSource.OpenFromInitializationString(lpcOleConnect);
    if (FAILED(hr))
    {
        cout<<DAM<<": Unable to connect to data source "<<OLE2T(lpcOleConnect)<<endl;
    }
    else
    {
        hr = dbSession.Open(dbDataSource);
        if (FAILED(hr))
        {
            cout<<DAM<<": Couldn't create session on data source "<<OLE2T(lpcOleConnect)<<endl;
        }
        else
        {
            CComVariant var;
            hr = dbDataSource.GetProperty(DBPROPSET_DATASOURCEINFO, DBPROP_DATASOURCENAME, &var);
            if (FAILED(hr) || (var.vt == VT_EMPTY))
            {
                cout<<DAM<<": No Data Source Name Specified."<<endl;
            }
            else
            {
                cout<<DAM<<": Successfully connected to database. Data source name:\n  "
                    <<COLE2T(var.bstrVal)<<endl;
                
                // Prepare SQL query.
                LPCOLESTR query = L"SELECT Customers.[Company], Customers.[First Name] FROM Customers;";
                cout<<DAM<<": SQL query:\n  "<<OLE2T(query)<<endl;
    
                // Excecute the query and create a record set
                CCommand<CDynamicStringAccessor> cmd;
                hr = cmd.Open(dbSession, query);
                DBORDINAL colCount = cmd.GetColumnCount();
                if (SUCCEEDED(hr) && 0 < colCount)
                {
                    cout<<DAM<<": Retrieve schema info for the given result set: "<<endl;
                    DBORDINAL cColumns;
                    DBCOLUMNINFO* rgInfo = NULL;
                    OLECHAR* pStringsBuffer = NULL;
                    cmd.GetColumnInfo(&cColumns, &rgInfo, &pStringsBuffer);
                    for (int col=0; col < (int)colCount; col++)
                    {
                        cout<<" | "<<OLE2T(rgInfo[col].pwszName);
                    }
                    cout<<endl;

                    cout<<DAM<<": Fetch the actual data: "<<endl;
                    int rowCount = 0;
                    CRowset<CDynamicStringAccessor>* pRS = (CRowset<CDynamicStringAccessor>*)&cmd;
                    // Loop through the rows in the result set
                    while (pRS->MoveNext() == S_OK)
                    {
                        for (int col=1; col <= (int)colCount; col++)
                        {
                            CHAR* szValue = cmd.GetString(col);
                            cout<<" | "<<szValue;
                        }
                        cout<<endl;
                        rowCount++;
                    }
                    cout<<DAM<<": Total Row Count: "<<rowCount<<endl;
                }                   
                else
                {
                    cout<<DAM<<": Error: Number of fields in the result set is 0."<<endl;
                }
            }  
        }
    }

    dbDataSource.Close();
    dbSession.Close();
    cout<<DAM<<": Cleanup. Done."<<endl;

    // Release the Component Object Module Library (COM)
    CoUninitialize();
    return hr;
}